package com.hkfn.rfb.common.utils;

import java.math.BigInteger;

public class HexUtil {

    private static final char[] DIGITS_LOWER = {'0', '1', '2', '3', '4', '5',
            '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'};

    private static final char[] DIGITS_UPPER = {'0', '1', '2', '3', '4', '5',
            '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'};

    private static String hexStr = "0123456789ABCDEF";
    private static String[] binaryArray =
            {"0000", "0001", "0010", "0011",
                    "0100", "0101", "0110", "0111",
                    "1000", "1001", "1010", "1011",
                    "1100", "1101", "1110", "1111"};

    public static char[] encodeHex(byte[] data) {
        return encodeHex(data, true);
    }

    public static char[] encodeHex(byte[] data, boolean toLowerCase) {
        return encodeHex(data, toLowerCase ? DIGITS_LOWER : DIGITS_UPPER);
    }

    protected static char[] encodeHex(byte[] data, char[] toDigits) {
        if (data == null)
            return null;
        int l = data.length;
        char[] out = new char[l << 1];
        for (int i = 0, j = 0; i < l; i++) {
            out[j++] = toDigits[(0xF0 & data[i]) >>> 4];
            out[j++] = toDigits[0x0F & data[i]];
        }
        return out;
    }

    public static String encodeHexStr(byte[] data) {
        return encodeHexStr(data, true);
    }

    public static String encodeHexStr(byte[] data, boolean toLowerCase) {
        return encodeHexStr(data, toLowerCase ? DIGITS_LOWER : DIGITS_UPPER);
    }


    protected static String encodeHexStr(byte[] data, char[] toDigits) {
        return new String(encodeHex(data, toDigits));
    }

    public static String formatHexString(byte[] data) {
        return formatHexString(data, false);
    }

    public static String formatHexString(byte[] data, boolean addSpace) {
        if (data == null || data.length < 1)
            return null;
        StringBuilder sb = new StringBuilder();
        for (int i = 0; i < data.length; i++) {
            String hex = Integer.toHexString(data[i] & 0xFF);
            if (hex.length() == 1) {
                hex = '0' + hex;
            }
            sb.append(hex);
            if (addSpace)
                sb.append(" ");
        }
        return sb.toString().trim();
    }

    public static byte[] decodeHex(char[] data) {

        int len = data.length;

        if ((len & 0x01) != 0) {
            throw new RuntimeException("Odd number of characters.");
        }

        byte[] out = new byte[len >> 1];

        // two characters form the hex value.
        for (int i = 0, j = 0; j < len; i++) {
            int f = toDigit(data[j], j) << 4;
            j++;
            f = f | toDigit(data[j], j);
            j++;
            out[i] = (byte) (f & 0xFF);
        }

        return out;
    }


    protected static int toDigit(char ch, int index) {
        int digit = Character.digit(ch, 16);
        if (digit == -1) {
            throw new RuntimeException("Illegal hexadecimal character " + ch
                    + " at index " + index);
        }
        return digit;
    }

    /**
     * 将十六进制转换为字节数组
     *
     * @param hexString
     * @return
     */
    public static byte[] hexStringToBytes(String hexString) {
        if (hexString == null || hexString.equals("")) {
            return null;
        }
        hexString = hexString.toUpperCase();
        int length = hexString.length() / 2;
        char[] hexChars = hexString.toCharArray();
        byte[] d = new byte[length];
        for (int i = 0; i < length; i++) {
            int pos = i * 2;
            d[i] = (byte) (charToByte(hexChars[pos]) << 4 | charToByte(hexChars[pos + 1]));
        }
        return d;
    }

    public static byte charToByte(char c) {
        return (byte) "0123456789ABCDEF".indexOf(c);
    }

    public static String extractData(byte[] data, int position) {
        return HexUtil.formatHexString(new byte[]{data[position]});
    }

    //將16進制字符串轉換為10進制數字
    public static int decodeHEXToInt(String hexs) {
        BigInteger bigint = new BigInteger(hexs, 16);
        int numb = bigint.intValue();
        return numb;
    }

    /**
     * @param bArray
     * @return 转换为二进制字符串
     */
    public static String bytes2BinaryStr(byte[] bArray) {

        String outStr = "";
        int pos = 0;
        for (byte b : bArray) {
            //高四位
            pos = (b & 0xF0) >> 4;
            outStr += binaryArray[pos];
            //低四位
            pos = b & 0x0F;
            outStr += binaryArray[pos];
        }
        return outStr;

    }

    /**
     * @param bytes
     * @return 将二进制转换为十六进制字符输出
     */
    public static String BinaryToHexString(byte[] bytes) {

        String result = "";
        String hex = "";
        for (int i = 0; i < bytes.length; i++) {
            //字节高4位
            hex = String.valueOf(hexStr.charAt((bytes[i] & 0xF0) >> 4));
            //字节低4位
            hex += String.valueOf(hexStr.charAt(bytes[i] & 0x0F));
            result += hex + " ";
        }
        return result;
    }

    /**
     * 每4个二进制位转换为1个十六进制位
     * @param input
     * @return
     */
    public static String bin2hex(String input) {
        if (null == input){
            input = "";
        }
        StringBuilder sb = new StringBuilder();
        int len = input.length();
        for (int i = 0; i < len / 4; i++){
            //每4个二进制位转换为1个十六进制位
            String temp = input.substring(i * 4, (i + 1) * 4);
            int tempInt = Integer.parseInt(temp, 2);
            String tempHex = Integer.toHexString(tempInt).toUpperCase();
            sb.append(tempHex);
        }

        return sb.toString();
    }

    /**
     * @param hexString
     * @return 将十六进制转换为字节数组
     */
    public static byte[] HexStringToBinary(String hexString) {
        return hexStringToBytes(hexString);
    }

    /**
     * 10进制转16进制
     *
     * @param x
     * @return
     */
    public static String int10ToHex(Integer x) {
        return int10ToHex(x, 4);
    }

    /**
     * 10进制转16进制
     *
     * @param x
     * @return
     */
    public static String int10ToHex(Integer x, int size) {
        StringBuilder stringBuilder = new StringBuilder();
        String value = x.toHexString(x);
        if (value.length() < size) {
            for (int i = 0; i < size - value.length(); i++) {
                stringBuilder.append("0");
            }
        }
        stringBuilder.append(value);
        return stringBuilder.toString().substring(0, size).toUpperCase();
    }

    /**
     * 16进制转10进制
     *
     * @param hex
     * @return
     */
    public static Integer hexToInt10(String hex) {
        Integer x = Integer.parseInt(hex, 16);
        return x;
    }

    /**
     * 有符号16进制转10进制
     *
     * @param hex
     * @return
     */
    public static Integer signHexToInt10(String hex) {
        Integer x = Integer.parseInt(String.valueOf((Integer.valueOf(hex, 16)).shortValue()), 10);
        return x;
    }


    /**
     * 有符号16进制转10进制
     *
     * @param x
     * @return
     */
    public static String signInt10ToHex(Integer x, int size) {
        StringBuilder stringBuilder = new StringBuilder();
        String value = x.toHexString(x);
        if (value.length() < size) {
            for (int i = 0; i < size - value.length(); i++) {
                stringBuilder.append("0");
            }
        } else {
            value = value.substring(value.length() - size);
        }
        stringBuilder.append(value);
        return stringBuilder.toString();
    }

    /**
     * 16进制转10进制
     *
     * @param hex
     * @return
     */
    public static Long hexToLong10(String hex) {
        Long x = Long.parseLong(hex, 16);
        return x;
    }

    /**
     * 10进制转16进制
     *
     * @param x
     * @return
     */
    public static String long10ToHex(Long x, int size) {
        StringBuilder stringBuilder = new StringBuilder();
        String value = x.toHexString(x);
        if (value.length() < size) {
            for (int i = 0; i < size - value.length(); i++) {
                stringBuilder.append("0");
            }
        }
        stringBuilder.append(value);
        return stringBuilder.toString().substring(0, size);
    }


    /**
     * int到byte[] 由高位到低位
     *
     * @param i 需要转换为byte数组的整行值。
     * @return byte数组
     */
    public static byte[] intToByteArray(int i) {
        byte[] result = new byte[4];
        result[0] = (byte) ((i >> 24) & 0xFF);
        result[1] = (byte) ((i >> 16) & 0xFF);
        result[2] = (byte) ((i >> 8) & 0xFF);
        result[3] = (byte) (i & 0xFF);
        return result;
    }

    public static String bytes2HexString(byte[] b) {
        StringBuffer result = new StringBuffer();
        for (int i = 0; i < b.length; i++) {
            result.append(String.format("%02X", b[i]));
        }
        return result.toString();
    }

    /**
     * @param buf
     * @return
     * @description 将二进制转换成16进制
     */
    public static String parseByte2HexStr(byte buf[]) {
        StringBuffer sb = new StringBuffer();
        for (int i = 0; i < buf.length; i++) {
            String hex = Integer.toHexString(buf[i] & 0xFF);
            if (hex.length() == 1) {
                hex = '0' + hex;
            }
            sb.append(hex.toUpperCase());
        }
        return sb.toString();
    }

    /**
     * @param src 16进制字符串
     * @return 字节数组
     * @throws
     * @Title:hexString2Bytes
     * @Description:16进制字符串转字节数组
     */
    public static byte[] hexString2Bytes(String src) {
        int l = src.length() / 2;
        byte[] ret = new byte[l];
        for (int i = 0; i < l; i++) {
            ret[i] = Integer.valueOf(src.substring(i * 2, i * 2 + 2), 16).byteValue();
        }
        return ret;
    }

    /**
     * @param strPart    字符串
     * @param tochartype hex目标编码
     * @return 16进制字符串
     * @throws
     * @Title:string2HexString
     * @Description:字符串转16进制字符串
     */
    public static String string2HexString(String strPart, String tochartype) {
        try {
            return bytes2HexString(strPart.getBytes(tochartype));
        } catch (Exception e) {
            return "";
        }
    }

    /**
     * @param src 16进制字符串
     * @return 字节数组
     * @throws
     * @Title:hexString2String
     * @Description:16进制字符串转字符串
     */
    public static String hexString2String(String src, String oldchartype, String chartype) {
        try {
            byte[] bts = hexString2Bytes(src);
            if (oldchartype.equals(chartype))
                return new String(bts, oldchartype);
            else
                return new String(new String(bts, oldchartype).getBytes(), chartype);
        } catch (Exception e) {
            return src;
        }
    }

    //string转hex(utf8)
    public static String string2HexUTF8(String strPart) {

        return string2HexString(strPart, "UTF-8");
    }

    //string转hex(gb2312)
    public static String string2HexGBK(String strPart) {

        return string2HexString(strPart, "GBK");
    }

    //hex转string(utf8)
    public static String hexUTF82String(String src) {
        return hexString2String(src, "UTF-8", "UTF-8");
    }

    //hex转string(gb2312)
    public static String hexGBK2String(String src) {

        return hexString2String(src, "GBK", "UTF-8");
    }


    /**
     * 16进制直接转换成为字符串(无需Unicode解码)
     *
     * @param hexStr
     * @return
     */
    public static String hexStr2Str(String hexStr) {
        hexStr = hexStr.replace(" ", "");
        String str = "0123456789ABCDEF";
        char[] hexs = hexStr.toCharArray();
        byte[] bytes = new byte[hexStr.length() / 2];
        int n;
        for (int i = 0; i < bytes.length; i++) {
            n = str.indexOf(hexs[2 * i]) * 16;
            n += str.indexOf(hexs[2 * i + 1]);
            bytes[i] = (byte) (n & 0xff);
        }
        return new String(bytes);
    }

    //字符串转换为ascii
    public static String StringToA(String content) {
        String result = "";
        int max = content.length();
        for (int i = 0; i < max; i++) {
            char c = content.charAt(i);
            int b = (int) c;
            result = result + b;
        }
        return result;
    }

    /**
     * 将16进制 ASCII转成字符串
     *
     * @param hexValue
     * @return
     */
    public static String asciiToString(String hexValue) {
        StringBuffer sbu = new StringBuffer();
        for (int i = 0; i < hexValue.length(); i += 2) {
            String substring = hexValue.substring(i, i + 2);
            if (!"00".equals(substring)) {// 字符为空时不处理
                sbu.append((char) Integer.parseInt(substring, 16));
            }
        }
        return sbu.toString();
    }

    /**
     * 将字符串转成16进制ASCII
     *
     * @param strValue
     * @return
     */
    public static String stringToHexAscii(String strValue) {
        StringBuffer sbu = new StringBuffer();
        if (null == strValue){
            strValue = "";
        }
        char[] chars = strValue.toCharArray();
        for (int i = 0; i < chars.length; i++) {
            sbu.append(HexUtil.int10ToHex((int) chars[i], 2));
        }
        return sbu.toString().toUpperCase();
    }

    /**
     * 将字符串转成16进制ASCII 位数不足用空格在前面填充
     *
     * @param strValue
     * @return
     */
    public static String stringToHexAsciiBySpace(String strValue, int byteNum) {
        StringBuffer sbu = new StringBuffer();
        if (null == strValue){
            strValue = "";
        }
        char[] chars = strValue.toCharArray();
        for (int i = 0; i < byteNum - chars.length; i++) {
            // 不足用空格填充
            sbu.append("20");
        }
        for (int i = 0; i < chars.length; i++) {
            sbu.append(HexUtil.int10ToHex((int) chars[i], 2));
        }
        return sbu.toString().toUpperCase();
    }

    /**
     * 将字符串转成ASCII 尽量用上面的方法固定返回位数
     *
     * @param strValue
     * @return
     */
    public static String stringToAscii(String strValue) {
        StringBuffer sbu = new StringBuffer();
        char[] chars = strValue.toCharArray();
        for (int i = 0; i < chars.length; i++) {
            if (i != chars.length - 1) {
                sbu.append((int) chars[i]).append(",");
            } else {
                sbu.append((int) chars[i]);
            }
        }
        return sbu.toString();
    }
}